package cn.virens.common.init;

import cn.hutool.core.util.ReUtil;
import cn.virens.common.exception.APIException;
import cn.virens.common.utils.Assert;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class InitExecutorFactory {
    private final Map<String, InitExecutorInter> funStack = new ConcurrentHashMap<>();

    protected String format(Map<String, Object> map, String sql) throws APIException {
        return fmt2(map, fmt1(map, Assert.isNull(sql, "传入SQL不可为NULL")));
    }

    /**
     * 生成SQL生成器
     */
    public InitExecutor executor() throws APIException {
        return new InitExecutor(this);
    }

    /**
     * SQL生成:根据key值获取map中的参数,如果不存在，根据fun调用对应的生成器生成
     *
     * @param map 模版参数
     * @param sql 原始文本
     * @return 可用sql
     * @throws APIException 一般异常
     */
    private String fmt1(Map<String, Object> map, String sql) throws APIException {
        return ReUtil.replaceAll(sql, "\\{@(\\w+):(\\w+)\\}", m -> {
            return str(map.computeIfAbsent(m.group(2), k -> {
                return call(map, m.group(1));
            }));
        });
    }

    /**
     * SQL生成:根据key值获取map中的参数
     *
     * @param map 模版参数
     * @param sql 原始文本
     * @return 可用sql
     * @throws APIException 一般异常
     */
    private String fmt2(Map<String, Object> map, String sql) throws APIException {
        return ReUtil.replaceAll(sql, "\\{(\\w+)\\}", m -> {
            return str(map.get(m.group(1)));
        });
    }

    /**
     * 调用函数对参数进行生成
     *
     * @param map 模版参数
     * @param key 动态变量KEK
     * @return 生成值
     * @throws APIException 一般异常
     */
    private Object call(Map<String, Object> map, String key) throws APIException {
        InitExecutorInter fun = funStack.get(key);

        if (fun != null && map != null) {
            return fun.apply(map);
        } else {
            return "";
        }
    }

    private static String str(Object obj) throws APIException {
        return obj != null ? sql(obj.toString()) : "";
    }

    /**
     * 防止用户发送SQL注入相关词汇
     *
     * @param inputKeyword SQL文本
     * @return 安全SQL
     * @throws APIException 一般异常
     */
    private static String sql(String inputKeyword) throws APIException {
        if (inputKeyword != null && !inputKeyword.isEmpty()) {
            return inputKeyword.replaceAll("([';])+|(--)+", "");
        } else {
            return "";
        }
    }

    /**
     * 添加可用的函数
     *
     * @param fun      函数KEY
     * @param function 函数实现
     */
    public void addFun(String fun, InitExecutorInter function) {
        this.funStack.put(fun, function);
    }

}
